package org.sean.framework.canary.core;

import lombok.extern.slf4j.Slf4j;
import org.sean.framework.canary.loadbalancer.predicate.MainPredicate;
import org.sean.framework.canary.loadbalancer.predicate.MasterPredicate;
import org.sean.framework.canary.loadbalancer.predicate.ServerPredicate;
import org.sean.framework.util.ObjectUtil;
import org.sean.framework.util.StringUtil;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 灰度工具
 *
 * @author xielei
 */
@Slf4j
public class CanaryUtils {

    private static CanaryProperties canaryProperties;
    private static Map<String, CanaryProperties.Canary> clientIdRules;
    private static Map<String, CanaryProperties.Canary> deviceIdRules;
    private static Map<String, CanaryProperties.Canary> targetIdRules;
    private static Map<String, CanaryProperties.Canary> targetIpRules;

    /**
     * 初始化规则
     *
     * @param properties 灰度配置
     */
    public static synchronized void initRules(CanaryProperties properties) {
        log.debug("初始化灰度规则");
        MainPredicate.reset();
        ServerPredicate.reset();
        canaryProperties = properties;
        clientIdRules = new HashMap<>();
        deviceIdRules = new HashMap<>();
        targetIdRules = new HashMap<>();
        targetIpRules = new HashMap<>();
        properties.getRules().forEach(item -> {
            if (StringUtil.isNotEmpty(item.getClientId())) {
                clientIdRules.put(item.getClientId(), item);
            }
            if (StringUtil.isNotEmpty(item.getDeviceId())) {
                deviceIdRules.put(item.getDeviceId(), item);
            }
            if (StringUtil.isNotEmpty(item.getTargetId())) {
                targetIdRules.put(item.getTargetId(), item);
            }
            if (StringUtil.isNotEmpty(item.getTargetIp())) {
                targetIpRules.put(item.getTargetIp(), item);
            }
        });

        CanaryProperties.Default main = properties.getMain();

        if (main != null) {
            // 全局label
            String label = main.getLabel();
            if (StringUtil.isNotEmpty(label)) {
                MainPredicate.setDefaultLabel(label);
            }
            // 服务对应的label
            Set<CanaryProperties.Server> servers = main.getServers();
            if (ObjectUtil.isNotEmpty(servers)) {
                ServerPredicate.setServers(servers);
            }
        }

        log.debug("RULES : " + properties.getRules());
        log.debug("MAIN : " + properties.getMain());
        log.debug("BLACK_IPS : " + properties.getBlackIps());
        log.debug("WHITE_IPS : " + properties.getWhiteIps());
    }

    /**
     * 取label
     *
     * @param clientId clientId
     * @return 灰度规则
     */
    public static CanaryProperties.Canary getLabelByClientId(String clientId) {
        return clientIdRules.get(clientId);
    }

    /**
     * 取label
     *
     * @param deviceId deviceId
     * @return 灰度规则
     */
    public static CanaryProperties.Canary getLabelByDeviceId(String deviceId) {
        return deviceIdRules.get(deviceId);
    }

    /**
     * 取label
     *
     * @param targetId targetId
     * @return 灰度规则
     */
    public static CanaryProperties.Canary getLabelByTargetId(String targetId) {
        return targetIdRules.get(targetId);
    }

    /**
     * 取label
     *
     * @param targetIp targetIp
     * @return 灰度规则
     */
    public static CanaryProperties.Canary getLabelByTargetIp(String targetIp) {
        return targetIpRules.entrySet().stream().filter(item -> {
            try {
                return item.getKey().equals(targetIp) || item.getKey().matches(targetIp);
            } catch (Exception e) {
                return false;
            }
        }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).get(targetIp);
    }

    /**
     * 当前服务Label
     *
     * @return label
     */
    public static String getLocalLabel() {
        return canaryProperties.getLocalLabel();
    }

    /**
     * 取Label
     *
     * @param serviceInstance 服务实例
     * @return label
     */
    public static String getServerLabel(ServiceInstance serviceInstance) {
        return Optional.ofNullable(getMetadata(serviceInstance).get(CanaryProperties.METADATA_LABEL)).orElse(MasterPredicate.METADATA_LABEL_DEFAULT);
    }

    /**
     * 取Metadata
     *
     * @param serviceInstance 服务实例
     * @return 元数据
     */
    public static Map<String, String> getMetadata(ServiceInstance serviceInstance) {
        return serviceInstance.getMetadata();
    }

    /**
     * 当前服务IP
     *
     * @return ip
     */
    public static String getLocalIp() {
        return canaryProperties.getLocalIp();
    }

    /**
     * 当前服务 Service Id
     *
     * @return serviceId
     */
    public static String getLocalServiceId() {
        return canaryProperties.getLocalServiceId();
    }

    /**
     * 当前服务实例ID
     *
     * @return 实例ID
     */
    public static String getLocalInstanceId() {
        return canaryProperties.getLocalInstanceId();
    }

    /**
     * 指定服务是否可选, 黑名单IP
     *
     * @param serverHost 服务IP
     * @return 是否可选中
     */
    public static boolean canChoose(String serverHost) {
        boolean isWhiteHost = canaryProperties.getWhiteIps().stream().anyMatch(host -> {
            PathMatcher matcher = new AntPathMatcher();
            return matcher.match(host, serverHost);
        });

        return isWhiteHost || canaryProperties.getBlackIps().stream().noneMatch(host -> {
            PathMatcher matcher = new AntPathMatcher();
            return matcher.match(host, serverHost);
        });
    }

}
